home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Libraries / grayimage / write_tiff.cc < prev    next >
Encoding:
Text File  |  1994-06-30  |  12.2 KB  |  275 lines  |  [TEXT/R*ch]

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *               Grayscale Image
  6.  *
  7.  *        Write an image into a file in the TIFF format
  8.  *
  9.  * The present TIFF writer creates a Class G TIFF file (for gray-scale
  10.  * images), See Appendix G of the TIFF specification. 
  11.  *
  12.  * The program writes the following required tags
  13.  *    NewSubfileType
  14.  *    ImageWidth
  15.  *    ImageLength
  16.  *    RowsPerStrip    (To make strips around 8K)
  17.  *    StripOffsets
  18.  *    Stripile) {}    // Value is a part of the item, and
  19.                     // is written along with the item
  20.  
  21. public:
  22.   ScalarTIFFDE(const short _tag, const SHORT _value)
  23.     : TIFFDirectoryItem(_tag,SHORT,1,(unsigned long)_value << 16) {}
  24.   ScalarTIFFDE(const short _tag, const LONG _value)
  25.     : TIFFDirectoryItem(_tag,LONG,1,_value) {}
  26.   ~ScalarTIFFDE(void) {}
  27. };
  28.  
  29.                 // Write this item into a file
  30. void ScalarTIFFDE::write(EndianIO& file)
  31. {
  32.   file.write_short(tag);
  33.   file.write_short(type);
  34.   file.write_long(count);
  35.   file.write_long(val_offset);
  36. }
  37.  
  38.  
  39.                 // String item, the string itself is written
  40.                 // after the IFD, the val_offset field of
  41.                 // the item stores an offset to the string
  42.                 // characters.
  43. class StringTIFFDE : public TIFFDirectoryItem
  44. {
  45. protected:
  46.   void write(EndianIO& file);        // Write this field into a file
  47.   void write_value(EndianIO& file);    // Write the body of the string
  48.                     // (after the directory is written)
  49.  
  50.   long int offset_for_val;        // for the val_offset field
  51.  
  52. public:
  53.   StringTIFFDE(const short _tag, const char * str)
  54.     : TIFFDirectoryItem(_tag,ASCII, str == 0 || str[0] == '\0' ? //empty string
  55.             0 : strlen(str)+1,(long)str) {}
  56.   ~StringTIFFDE(void) {}
  57. };
  58.  
  59.                 // Write this item into a file
  60. void StringTIFFDE::write(EndianIO& file)
  61. {
  62.   assert( count > 0 );
  63.   file.write_short(tag);
  64.   file.write_short(type);
  65.   file.write_long(count);
  66.   offset_for_val = file.tellp();
  67.   file.write_long(0);            // write a dummy for now
  68. }
  69.  
  70.                 // Write the body of the string,
  71.                 // Note, a padding may be necessary to
  72.                 // make the string end at a word boundary
  73. void StringTIFFDE::write_value(EndianIO& file)
  74. {
  75.   long int pos = file.tellp();        // where are we now
  76.                     // Write a body of the string, '\0'
  77.                     // and (possible) an extra byte
  78.   file.write((char *)val_offset,(strlen((char *)val_offset)+1+1) & ~1);
  79.                         // to keep word-boundary align
  80.   long int pos_new = file.tellp();
  81.   assert( file.seekp(offset_for_val).good() );
  82.   file.write_long(pos);            // Write the offset within the dir elem
  83.   assert( file.seekp(pos_new).good() );    // Restore the file position 
  84.                     // to continue writing
  85. }
  86.  
  87.  
  88.                 // Directory item that refers to an array
  89.                 // (that can contain strip offsets, strip
  90.                 // byte counts, or other info specific to
  91.                 // each strip)
  92. class ArrayTIFFDE : public TIFFDirectoryItem
  93. {
  94. protected:
  95.   virtual void write(EndianIO& file);    // Write this field into a file
  96.   virtual void write_value(EndianIO& file);    // Write the body of the array
  97.                     // (after the directory is written)
  98.  
  99.   long int offset_for_val;        // for the val_offset field
  100.   long * array;
  101.   
  102. public:
  103.   ArrayTIFFDE(const short _tag, const long no_elems);
  104.   ~ArrayTIFFDE(void);
  105.   long& operator [] (const int index)    // Get hold of an element of the array
  106.       { assert( index >= 0 && index < count ); return array[index]; }
  107. };
  108.  
  109.                 // Constructor - allocate the array
  110. ArrayTIFFDE::ArrayTIFFDE(const short _tag, const long no_elems) 
  111.     : TIFFDirectoryItem(_tag, LONG, no_elems, 0)
  112. {
  113.   assert( count > 0 );
  114.   array = new long[count];
  115. }
  116.  
  117.  
  118.                 // Dispose of the array
  119. ArrayTIFFDE::~ArrayTIFFDE(void)
  120. {
  121.   assert( array != 0 );
  122.   delete array;
  123.   array = 0;
  124. }
  125.  
  126.  
  127.                 // Write this item into a file
  128. void ArrayTIFFDE::write(EndianIO& file)
  129. {
  130.   assert( count > 0 );
  131.   file.write_short(tag);
  132.   file.write_short(type);
  133.   file.write_long(count);
  134.   offset_for_val = file.tellp();
  135.   file.write_long(0);            // write a dummy for now
  136. }
  137.  
  138.                 // Write array elements (if more than 1)
  139.                 // after the directory
  140. void ArrayTIFFDE::write_value(EndianIO& file)
  141. {
  142.   long int pos;                // Where the array is to be written
  143.   register int i;
  144.   if( count == 1 )            // If there is only one elem, keep
  145.     pos = array[0];            // the offset with the dir elem itself
  146.   else
  147.   {
  148.     pos = file.tellp();            // Write the array separately
  149.     for(i=0; i<count; i++)
  150.       file.write_long(array[i]);
  151.   }
  152.   long int pos_new = file.tellp();
  153.   assert( offset_for_val > 0 && file.seekp(offset_for_val).good() );
  154.   file.write_long(pos);            // Write the offset within the dir elem
  155.   assert( file.seekp(pos_new).good() );    // Restore the file position 
  156.                     // to continue writing
  157. }
  158.  
  159.                 // Rational number: an array of two LONGs
  160. class RationalTIFFDE : public ArrayTIFFDE
  161. {
  162.   virtual void write(EndianIO& file);    // Write this field into a file
  163. public:
  164.   RationalTIFFDE(const short _tag, const int numerator,const int denominator)
  165.     : ArrayTIFFDE(_tag,2)
  166.     { array[0] = numerator; array[1] = denominator; type = RATIONAL; }
  167. };
  168.  
  169.                 // Write this item into a file: only one
  170.                 // modification: a rational has count 1, though
  171.                 // it's an array of 2 longs
  172. void RationalTIFFDE::write(EndianIO& file)
  173. {
  174.   assert( count == 2 );
  175.   count = 1;                // temporarily: that's what we write
  176.   ArrayTIFFDE::write(file);        // into the tag
  177.   count = 2;
  178. }
  179.  
  180.  
  181.                 // Strip item, that refers to an array
  182.                 // that contains offsets to the strips (set
  183.                 // of rows) of the image
  184.                 // No compression is used at present
  185. class StripTIFFDE : public ArrayTIFFDE
  186. {
  187. protected:
  188.   void write_value(EndianIO& file);    // Write the array of strip ptrs
  189.                     // and strips themselves
  190.                     // (after the directory is written)
  191.  
  192.   ArrayTIFFDE    strip_byte_counts;    // It is not necessary unless compress-
  193.                     // ion is used; but neverthelesss
  194.   short rows_per_strip;
  195.   const IMAGE& image;
  196.  
  197. public:
  198.   StripTIFFDE(const short _no_strips, const short _rows_per_strip,
  199.           const IMAGE& _image)
  200.     : ArrayTIFFDE(TIFFTAG_STRIPOFFSETS,_no_strips),
  201.       strip_byte_counts(TIFFTAG_STRIPBYTECOUNTS,_no_strips),
  202.       rows_per_strip(_rows_per_strip), image(_image) {}
  203.   ~StripTIFFDE(void) {}
  204. };
  205.  
  206.                     // Write the array of strip ptrs
  207.                     // and strips themselves
  208.                     // (after the directory is written)
  209.                     // Note the trick! StripByteCount
  210.                     // has a bigger tag, i.e. strip_byte_
  211.                     // count will be written AFTER the
  212.                     // strips are written, i.e., when
  213.                     // strip sizes are already known
  214. void StripTIFFDE::write_value(EndianIO& file)
  215. {
  216.   assert( count > 0 );
  217.   register int strip;
  218.   for(strip=0; strip<count; strip++)
  219.   {
  220.     array[strip] = file.tellp();    // where are we now, beg of a strip
  221.     register int i,j;            // Writing a strip
  222.     for(i=strip*rows_per_strip; 
  223.     i<(strip+1)*rows_per_strip && i < image.q_nrows(); i++)
  224.       for(j=0; j<image.q_ncols(); j++)
  225.     file.write_byte(image(i,j));
  226.     strip_byte_counts[strip] = file.tellp() - array[strip];
  227.   }
  228.   ArrayTIFFDE::write_value(file);
  229. }
  230.  
  231. /*
  232.  *------------------------------------------------------------------------
  233.  *                Root module
  234.  */
  235.  
  236. void IMAGE::write_tiff(const char * file_name,const char * title) const
  237. {
  238.   is_valid();
  239.  
  240.   message("\nPreparing a TIFF file with name '%s'\n",file_name);
  241.  
  242.   EndianIO file(file_name,ios::out);
  243.  
  244.   TIFFHeader header;
  245.   header.write(file);
  246.  
  247.   ScalarTIFFDE subfile_tag(TIFFTAG_SUBFILETYPE,(long)0);
  248.   ScalarTIFFDE width_tag(TIFFTAG_IMAGEWIDTH,q_ncols());
  249.   ScalarTIFFDE length_tag(TIFFTAG_IMAGELENGTH,q_nrows());
  250.   ScalarTIFFDE compr_tag(TIFFTAG_COMPRESSION,(short)COMPRESSION_NONE);
  251.   ScalarTIFFDE phot_tag(TIFFTAG_PHOTOMETRIC,(short)PHOTOMETRIC_MINISBLACK);
  252.   ScalarTIFFDE resunit_tag(TIFFTAG_RESOLUTIONUNIT,(short)RESUNIT_INCH);
  253.                     // Means 72 pixels per unit (inch)
  254.   RationalTIFFDE xres_tag(TIFFTAG_XRESOLUTION,72,1);
  255.   RationalTIFFDE yres_tag(TIFFTAG_YRESOLUTION,72,1);
  256.  
  257.   ScalarTIFFDE samplesize_tag(TIFFTAG_SAMPLESPERPIXEL,(short)1);
  258.   assert( bits_per_pixel == 8 );
  259.   ScalarTIFFDE depth_tag(TIFFTAG_BITSPERSAMPLE,(short)8);
  260.  
  261.  
  262.   StringTIFFDE desc_tag(TIFFTAG_IMAGEDESCRIPTION, name );
  263.   StringTIFFDE docname_tag(TIFFTAG_DOCUMENTNAME, title );
  264.  
  265.   const int strip_target_size = 8*1024;
  266.   int rows_per_strip = strip_target_size / q_ncols();
  267.   int no_strips = (q_nrows() + rows_per_strip - 1)/rows_per_strip;
  268.   ScalarTIFFDE striprs_tag(TIFFTAG_ROWSPERSTRIP,(long)rows_per_strip);
  269.   StripTIFFDE  stripoffs_tag(no_strips, rows_per_strip, *this);
  270.  
  271.   subfile_tag.write_all(file);            
  272.   file.close();
  273. }
  274.  
  275.